# coding: utf-8

'''
Created on 27 avr. 2011

@author: shin


La classe modèle sera la classe mère du coeur du jeu (mère de business).
Il faudra lui donner les méthodes permettant de diriger le déroulement
du jeu lorsqu'il se passera telle ou telle action au niveau de la vue
C'est le controlleur qui lancera les méthodes du modèle après avoir vérifié 
leur cohérence pour le modèle.

Le modèle possède une liste des _observer de la vue qui intéresseront telle
ou telle action.

'''

from business.Activite       import Activite
from business.Damier         import Damier
from business.GameStatus     import GameStatus
from business.ElementFactory import ElementFactory
from business.Personnage     import Personnage
from stub.DaoEquipe          import DaoEquipe
from stub.DaoDamier          import DaoDamier

class Modele():
    '''
    La classe qui est aux commandes du combat.
       Elle gère le damier, l'activité, les personnages en fonction des
       demandes du contrôleur
    '''

    def __init__(self):
        '''
        Crée tous les attributs et les initialise à nul
        '''
        self._elements   = {}
        self._damierLink = None
        self._gameStatus = None
        self._observer   = None
        self._caseCible  = None
        self._persoJouer = None
        '''
        le lien à l'objet Personnage selectionné par le joueur
        '''
        self._activite = Activite(self._elements)


    
    def clicCase(self, nomCaseCible):
        if self._activite.competenceActive() == 1:
            self._prevoitCompetence(nomCaseCible)
        else:
            self._caseCible = nomCaseCible
            self._updateUiPersoCible()

        self._gameStatus.maj_terrain(self._elements[nomCaseCible])            
        self._notifyZone(self._gameStatus.terrain,    "uiTerrain")
        self._notifyCase(nomCaseCible)
    
    def _prevoitCompetence(self, nomCaseCible):
        # met à jour l'affichage sur la case
        if self._caseCible != None\
                and self._caseCible in self._activite.casesCiblesDisponibles():
            self._gameStatus.maj_caseDamier(self._caseCible, "Normal")
            self._gameStatus.maj_caseDamier(self._caseCible, "marque_choixPossible")
            self._notifyCase(self._caseCible)
        if nomCaseCible in self._activite.casesCiblesDisponibles():
            self._gameStatus.maj_caseDamier(nomCaseCible, "Normal")
            self._gameStatus.maj_caseDamier(nomCaseCible, "marque_ciblePossible")
        
        self._caseCible = nomCaseCible
        resultat = self._activite.prevoitCompetence(self._persoJouer,
                                                    nomCaseCible )
        if resultat:
            personnage = None
            for name in self._damierLink.contenu(nomCaseCible):
                personnage = self._elements[name]
                if isinstance(personnage, Personnage):
                    self._gameStatus.maj_perso(2, personnage, resultat)
            self._notifyZone(self._gameStatus.persoCible, "uiPerso2")
        else:
            self._updateUiPersoCible()

    
    def utiliseCompetence(self, nomCaseCible):
        '''
        fait appliquer la competence à la case ciblé
        '''
        if not self._activite.competenceActive(): return
        if self._activite.prochaineAction() != "Passe son tour":
            if not self._activite.utiliseCompetence(
                        self._persoJouer,
                        nomCaseCible ):
                return
            self._caseCible = nomCaseCible
            self._updateUiPersoCible()
        self._finDeTour()

    def _updateUiPersoCible(self):
        if self._caseCible == None: return
        self._gameStatus.maj_perso(2, None, None)
        personnage = None
        for name in self._damierLink.contenu(self._caseCible):
            personnage = self._elements[name]
            if isinstance(personnage, Personnage):
                self._gameStatus.maj_perso(2, personnage, None)
        self._notifyZone(self._gameStatus.persoCible, "uiPerso2")

    def _finDeTour(self):
        fin = self._testFinPartie()
        if fin:
            self._observer.finDePartie(fin)
            return
        
        self._activite.prochainTourPersonnage(self._persoJouer)
        self._persoJouer = self._activite.prochainTour(self._gameStatus)
        
        self._gameStatus.maj_caseDamier("Toutes", "Normal")
               
        self._notifyDamier()
        self._notifyZone(self._gameStatus.tour,     "uiTour")
        self._notifyZone(self._gameStatus.activite, "uiActivite")

        self._modifiePersoJouer()

    def _modifiePersoJouer(self):        
        '''
        selectionne le prochain personnage à joueur
        '''
        nomCase = self._damierLink.donnePosition(self._persoJouer.nom)
        self._gameStatus.maj_caseDamier(nomCase, "marque_selected")
        
        personnage = None
        for name in self._damierLink.contenu(nomCase):
            personnage = self._elements[name]
            if isinstance(personnage, Personnage):
                self._gameStatus.maj_perso(1, personnage, None)

                self._persoJouer = personnage
                
                if personnage.nom == self._persoJouer.nom:
                    self._gameStatus.maj_action(personnage)
                else:
                    self._gameStatus.maj_action(None)
        
        self._notifyZone(self._gameStatus.persoChoix, "uiPerso1")
        self._notifyZone(self._gameStatus.action,     "uiAction")
        self._notifyDamier()


    def _testFinPartie(self):
        j1 = 0
        j2 = 0
        for element in self._elements.values():
            if isinstance(element, Personnage) and not element.mort():
                if element.joueur == 1:
                    j1 += 1
                if element.joueur == 2:
                    j2 += 1

        if j1 == j2 == 0:
            return "égalité"
        if j1 == 0:
            return "1"
        if j2 == 0:
            return "2"
        return False

    def demandeCompetence(self, nomCompetence):
        '''
        l'utilisateur clic sur une nomCompetence
        (ex : mouvement dans le prototype)
        le controlleur demande l'utilisation de la competence
        par cette methode        
        '''
        self._gameStatus.maj_caseDamier("Toutes", "Normal")
        self._gameStatus.maj_caseDamier(
                    self._damierLink.donnePosition(self._persoJouer.nom),
                    "marque_selected" )
        self._notifyDamier()
        
        result = self._activite.demandeCompetence(
                     self._persoJouer,
                     nomCompetence )
        
        if result == "Passe son tour":
            self.utiliseCompetence(None)
            return
        
        for case in result[0]:
            self._gameStatus.maj_caseDamier(case, result[1])
            self._notifyCase(case)

    def nouveauCombat(self, partie):
        self._initialiseNouvellePartie()
        
        daoDamier = DaoDamier(partie)
        self._damierLink = Damier(daoDamier)
        self._activite.linkDamier(self._damierLink)
        self._gameStatus = GameStatus(self._damierLink)
        self._damierLink.linkGameStatus(self._gameStatus)
        self._damierLink.addObserver(self._observer)
        for case in daoDamier.terrainType.items():
            element = ElementFactory.build("Terrain", case[1])
            element.nom = case[0]
            self._elements[element.nom] = element
            
        self._resetAffichage()
        self._observer.afficheNouvellePartie(self._gameStatus)

    def _resetAffichage(self):
        self._gameStatus.maj_action(None)
        self._gameStatus.maj_activite(None)
        self._gameStatus.maj_damier(self._damierLink)
        self._gameStatus.maj_perso(1, None, None)
        self._gameStatus.maj_perso(2, None, None)
        self._gameStatus.maj_terrain(None)

    def _initialiseNouvellePartie(self):
        self._elements   = {}
        self._damierLink     = None
        self._gameStatus = None
        self._caseCible  = None
        self._persoJouer = None
        self._activite = Activite(self._elements)
    
    def creerPerso(self, nom, type, race):
        personnage = ElementFactory.build(type, race)
        personnage.nom = nom
        self._elements[nom] = personnage
        personnage.addObserver(self._observer.creePersonnage(nom))
    
    def creerEquipe(self, equipe1, equipe2):
        '''
        permet de créer les personnages pour chaque équipe
        '''
        for equipe in [equipe1, equipe2]:
            for i, nom in enumerate(equipe):
                self._elements[nom].joueur = i +1
                
    def positionneElement(self, element, position):
        '''
        place un element à une position sur le damier
        '''
        if element not in self._elements:
            raise Exception("L'élément " + element + " n'existe pas")
        self._damierLink.place(element, position)
        if self._elements[element].joueur == 1:
            self._elements[element].regardeDroite()
        else:
            self._elements[element].regardeGauche()
        
    def lancePartie(self):
        '''
        permet de lancer la partie
            en calculant l'ordre de jeu
            en lancant le premier tour
        '''
        self._activite.calculOrdreInitialDeJeu()
        self._persoJouer =\
            self._activite.prochainTour(self._gameStatus)
        self._notifyZone(self._gameStatus.tour,     "uiTour")
        self._notifyZone(self._gameStatus.activite, "uiActivite")
        self._modifiePersoJouer()


    def _notifyZone(self, nomZone, changement):
        self._observer.updateUiZone(nomZone, changement)

    def _notifyDamier(self):
        self._observer.updateUiDamier(self._gameStatus.damier)

    def _notifyCase(self, case):
        self._observer.updateUiCase(case,
                            self._gameStatus.damier.cases[case])

    def addObserver(self, observer):
        self._observer = observer
    